﻿#------------------------------------------------------------------------------
# 脚本功能：从 Microsoft Store 下载并安装应用包
# 支持类型：.Appx, .AppxBundle, .Msix, .MsixBundle
# 版本：1.0
#------------------------------------------------------------------------------

#------------------------------------------------------------------------------
# 函数：下载并安装应用包
# 参数：
#   -Uri: 应用商店URL
#   -Path: 下载路径
#   -IncludeBundle: 是否包含 .AppxBundle/.MsixBundle 文件
#------------------------------------------------------------------------------
function Download-AppPackages {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$Uri,
        [string]$Path = ".",
        [switch]$IncludeBundle
    )
    
    process {
        Write-Debug "开始处理下载请求: $Uri"
        $Path = (Resolve-Path $Path).Path
        Write-Debug "下载路径: $Path"
        
        # 创建结果存储数组
        $allPackages = @()
        
        # 获取下载链接
        try {
            Write-Host "正在获取应用包列表..." -ForegroundColor Cyan
            $WebResponse = Invoke-WebRequest -UseBasicParsing -Method 'POST' -Uri 'https://store.rg-adguard.net/api/GetFiles' -Body "type=url&url=$Uri&ring=Retail" -ContentType 'application/x-www-form-urlencoded'
            Write-Debug "成功获取响应，状态码: $($WebResponse.StatusCode)"
        }
        catch {
            Write-Host "获取应用包列表失败: $_" -ForegroundColor Red
            return
        }
        
        # 定义包类型和对应的筛选模式
        $packageTypes = @(
            @{ Type = "Appx"; Pattern = '*.appx*' },
            @{ Type = "Msixbundle"; Pattern = '*.msixbundle*' }
            @{ Type = "Msix"; Pattern = '*.Msix*' }
        )
        
        # 遍历处理每种包类型
        foreach ($pkgType in $packageTypes) {
            Write-Debug "处理 $($pkgType.Type) 类型的包"
            
            # 筛选符合条件的链接
            if ($pkgType.Type -eq "Appx" -and !$IncludeBundle) {
                # 排除 .AppxBundle 文件
                $LinksMatch = $WebResponse.Links | Where-Object { $_ -like $pkgType.Pattern -and $_ -notlike '*.appxbundle*' } | 
                              Where-Object { $_ -like '*_neutral_*' -or $_ -like "*_"+$env:PROCESSOR_ARCHITECTURE.Replace("AMD","X").Replace("IA","X")+"_*" } | 
                              Select-String -Pattern '(?<=a href=").+(?=" r)'
            }
            else {
                $LinksMatch = $WebResponse.Links | Where-Object { $_ -like $pkgType.Pattern } | 
                              Where-Object { $_ -like '*_neutral_*' -or $_ -like "*_"+$env:PROCESSOR_ARCHITECTURE.Replace("AMD","X").Replace("IA","X")+"_*" } | 
                              Select-String -Pattern '(?<=a href=").+(?=" r)'
            }
            
            $DownloadLinks = $LinksMatch.Matches.Value
            Write-Debug "找到 $($DownloadLinks.Count) 个 $($pkgType.Type) 包链接"
            
            # 分析并提取包信息
            foreach ($url in $DownloadLinks) {
                try {
                    Write-Debug "处理链接: $url"
                    $FileRequest = Invoke-WebRequest -Uri $url -UseBasicParsing -Method Head
                    $FileName = ($FileRequest.Headers["Content-Disposition"] | Select-String -Pattern '(?<=filename=).+').Matches.Value
                    
                    # 提取版本信息
                    if ($FileName -match '^(.+?)_(\d+\.\d+\.\d+\.\d+)_') {
                        $Name = $matches[1]
                        $Version = [System.Version]$matches[2]
                        
                        $allPackages += [PSCustomObject]@{
                            Name = $Name
                            Version = $Version
                            FileName = $FileName
                            Url = $url
                            Type = $pkgType.Type
                            Size = [math]::Round(($FileRequest.Headers["Content-Length"] / 1MB), 2)
                        }
                        
                        Write-Debug "提取包信息: $Name v$Version ($FileName)"
                    }
                    else {
                        Write-Debug "无法从文件名提取版本信息: $FileName"
                    }
                }
                catch {
                    Write-Debug "处理链接时出错: $_"
                }
            }
        }
        
        # 按名称分组，选择每个应用的最新版本
        $LatestPackages = $allPackages | Group-Object Name | ForEach-Object {
            $_.Group | Sort-Object Version -Descending | Select-Object -First 1
        }
        
        # 输出分析结果
        Write-Host "`n找到 $($allPackages.Count) 个应用包，将下载 $($LatestPackages.Count) 个最新版本" -ForegroundColor Green
        Write-Host "------------------------------------------------------------------------------" -ForegroundColor DarkGray
        
        if ($allPackages.Count -gt 0) {
            $allPackages | Sort-Object Name, Version | Format-Table Name, Version, @{Label="Type";Expression={$_.Type}}, @{Label="Size (MB)";Expression={$_.Size}}, FileName
        }
        
        # 下载最新版本
        foreach ($package in $LatestPackages) {
            Write-Host "`n下载最新版本: $($package.FileName) ($($package.Size) MB)" -ForegroundColor Cyan
            
            try {
                $FilePath = Join-Path $Path $package.FileName
                $FilePath = Resolve-NameConflict -Path $FilePath
                
                # 使用进度显示的方式下载文件
                $wc = New-Object System.Net.WebClient
                $wc.DownloadFile($package.Url, $FilePath)
                
                Write-Host "已保存到: $FilePath" -ForegroundColor Green
                Write-Debug "下载完成: $FilePath"
            }
            catch {
                Write-Host "下载失败: $($package.FileName)" -ForegroundColor Red
                Write-Host "错误详情: $_" -ForegroundColor Red
            }
        }
        
        # 返回下载的包信息
        return $LatestPackages
    }
}

#------------------------------------------------------------------------------
# 函数：解决文件名冲突
# 参数：
#   -Path: 文件路径
# 返回：无冲突的新路径
#------------------------------------------------------------------------------
function Resolve-NameConflict {
    param(
        [string]$Path
    )
    
    $newPath = $Path
    if (Test-Path $Path) {
        $i = 0
        $item = (Get-Item $Path)
        while (Test-Path $newPath) {
            $i += 1
            $newPath = Join-Path $item.DirectoryName ($item.BaseName+"($i)"+$item.Extension)
        }
        Write-Debug "文件名冲突，新文件名: $newPath"
    }
    
    return $newPath
}

#------------------------------------------------------------------------------
# 函数：安装应用包
# 参数：
#   -Path: 包含应用包的文件夹路径
#------------------------------------------------------------------------------
function Install-AppPackages {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$Path
    )
    
    process {
        $Path = (Resolve-Path $Path).Path
        Write-Host "`n开始安装应用包..." -ForegroundColor Cyan
        
        # 检查文件夹是否存在
        if (-not (Test-Path -Path $Path -PathType Container)) {
            Write-Host "错误：文件夹 '$Path' 不存在！" -ForegroundColor Red
            return
        }
        
        # 定义安装顺序
        $installOrder = @(
            @{ Type = "Appx"; Filter = "*.appx" },
            @{ Type = "AppxBundle"; Filter = "*.appxbundle" },
            @{ Type = "Msix"; Filter = "*.msix" },
            @{ Type = "MsixBundle"; Filter = "*.msixbundle" }
        )
        
        # 按顺序安装各种类型的包
        foreach ($pkgType in $installOrder) {
            Write-Host "`n正在查找 $($pkgType.Type) 文件..." -ForegroundColor Cyan
            $files = Get-ChildItem -Path $Path -Filter $pkgType.Filter -File
            
            if ($files.Count -eq 0) {
                Write-Host "未找到 $($pkgType.Type) 文件。" -ForegroundColor Yellow
                continue
            }
            
            Write-Host "找到 $($files.Count) 个 $($pkgType.Type) 文件，开始安装..." -ForegroundColor Green
            
            foreach ($file in $files) {
                Write-Host "`n正在安装: $($file.FullName)" -ForegroundColor Cyan
                
                try {
                    Add-AppxPackage -Path $file.FullName -ErrorAction Stop
                    Write-Host "成功安装: $($file.Name)" -ForegroundColor Green
                }
                catch {
                    Write-Host "安装失败: $($file.Name)" -ForegroundColor Red
                    Write-Host "错误详情: $_" -ForegroundColor Red
                }
            }
        }
        
        Write-Host "`n安装过程已完成！" -ForegroundColor Cyan
    }
}

#------------------------------------------------------------------------------
# 主脚本执行区域
#------------------------------------------------------------------------------
# 设置调试模式
# $DebugPreference = "Continue"

# 设置应用名称和应用ID变量
# $appName = "WinGet"
# $appId = "9NBLGGH4NNS1"

# 从id.ini文件读取应用名称和应用ID
$iniFile = Join-Path -Path $PSScriptRoot -ChildPath "id.ini"

if (Test-Path -Path $iniFile -PathType Leaf) {
    try {
        $iniContent = Get-Content -Path $iniFile -Raw -ErrorAction Stop
        $lines = $iniContent -split "`r`n|`r|`n"
        
        if ($lines.Count -ge 2) {
            $appName = $lines[0].Trim()
            $appId = $lines[1].Trim()
            
            Write-Host "从 $iniFile 读取配置:" -ForegroundColor Cyan
            Write-Host "  应用名称: $appName" -ForegroundColor White
            Write-Host "  应用ID: $appId" -ForegroundColor White
        }
        else {
            Write-Host "错误: $iniFile 文件至少需要两行内容" -ForegroundColor Red
            exit 1
        }
    }
    catch {
        Write-Host "读取 $iniFile 文件时出错: $_" -ForegroundColor Red
        exit 1
    }
}
else {
    Write-Host "错误: 未找到 $iniFile 文件" -ForegroundColor Red
    exit 1
}

# 创建下载文件夹
$targetFolder = Join-Path -Path $PSScriptRoot -ChildPath $appName
Write-Host "`n目标文件夹: $targetFolder" -ForegroundColor Cyan

# 检查文件夹是否存在
if (-not (Test-Path -Path $targetFolder -PathType Container)) {
    # 若不存在则创建文件夹
    New-Item -Path $targetFolder -ItemType Directory -Force | Out-Null
    Write-Host "已创建文件夹: $targetFolder" -ForegroundColor Green
} else {
    # 若存在则清空文件夹内容
    Write-Host "正在清空文件夹: $targetFolder..." -ForegroundColor Yellow
    Get-ChildItem -Path $targetFolder -Recurse | Remove-Item -Force -Recurse
    Write-Host "文件夹已清空" -ForegroundColor Green
}

# 执行下载
Write-Host "`n开始下载 $appName 应用包..." -ForegroundColor Cyan
Write-Host $appId
Write-Host "https://apps.microsoft.com/store/detail/$($appId)?hl=zh-CN&gl=CN"
$downloadedPackages = Download-AppPackages -Uri "https://apps.microsoft.com/store/detail/$($appId)?hl=zh-CN&gl=CN" -Path $targetFolder

# 执行安装
if ($downloadedPackages -and $downloadedPackages.Count -gt 0) {
    Write-Host "`n下载完成，开始安装过程..." -ForegroundColor Cyan
    Install-AppPackages -Path $targetFolder
} else {
    Write-Host "未下载任何应用包，安装过程取消。" -ForegroundColor Yellow}

# 清空下载
Write-Host "正在清空文件夹: $targetFolder..." -ForegroundColor Yellow
Get-ChildItem -Path $targetFolder -Recurse | Remove-Item -Force -Recurse
Write-Host "文件夹已清空" -ForegroundColor Green